package com.yonyou.crm.sys.org.service;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.yonyou.crm.common.field.relation.RefFieldRelation;
import com.yonyou.crm.sys.org.itf.ISysOrgBizService;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.yonyou.crm.common.biz.service.BaseBizServiceImpl;
import com.yonyou.crm.common.enumeration.entity.EnableStateEnum;
import com.yonyou.crm.common.enumeration.entity.OrgTypeEnum;
import com.yonyou.crm.common.enumeration.service.EnumBizServiceImpl;
import com.yonyou.crm.common.exception.CrmBusinessException;
import com.yonyou.crm.common.field.handler.FieldRelationHandler;
import com.yonyou.crm.common.field.relation.EnumFieldRelation;
import com.yonyou.crm.common.field.relation.FieldRelation;
import com.yonyou.crm.common.model.util.ModelUtil;
import com.yonyou.crm.common.page.entity.Page;
import com.yonyou.crm.cum.contact.service.ContactBizServiceImpl;
import com.yonyou.crm.sys.org.entity.SysOrgDO;
import com.yonyou.crm.sys.org.entity.SysOrgVO;
import com.yonyou.crm.sys.user.service.UserBizServiceImpl;
import com.yonyou.iuap.context.InvocationInfoProxy;

public class SysOrgBizServiceImpl extends BaseBizServiceImpl<SysOrgDO> implements ISysOrgBizService {
	
	@Autowired
	private EnumBizServiceImpl enumService;
	@Autowired
	private UserBizServiceImpl userService;
	@Autowired
	private SysOrgBizServiceImpl orgService;
	@Autowired
	private ContactBizServiceImpl contactService;
	
	/**
	 * 分页查询
	 * @param page
	 * @param paramMap
	 * @return
	 */
	public Page<SysOrgVO> getPage(Page<SysOrgVO> page, Map<String, Object> paraMap) {

		Page<SysOrgDO> doPage = null;
		if (paraMap != null) {
			doPage = super.pageSelect(SysOrgDO.class, page, paraMap.keySet().toArray(new String[0]), paraMap.values().toArray(new Object[0]));
		}
		else{
			doPage = super.pageSelect(SysOrgDO.class, page, null, null);
		}

		//根据当前登录人过滤集团
		doPage=getPageWithFilter(doPage);
		Page<SysOrgVO> voPage = ModelUtil.copyPageModel(doPage, SysOrgVO.class);
		trans(voPage.getData());
		return voPage;
	}

	/**
	 * 详情
	 * @param id
	 * @return
	 */
	public SysOrgVO getDetail(Long id) {
		SysOrgVO vo = ModelUtil.copyModel(dao.getById(SysOrgDO.class, id), SysOrgVO.class);
		trans(Arrays.asList(vo));
		return vo;
	}

	/**
	 * 新增
	 * @param vo
	 * @return
	 */
	public SysOrgVO insert(SysOrgVO vo) {
		SysOrgDO oDO = ModelUtil.copyModel(vo, SysOrgDO.class);
		return ModelUtil.copyModel(super.saveVO(oDO), SysOrgVO.class);  
	}
	
	@Override
	protected void beforeSaveVO(SysOrgDO oDO) {
		
		if (isExistCode(oDO.getCode(), null)) {
			throw new CrmBusinessException("组织编码不可重复");
		}
		
		//同组织下部门名称、简称唯一
		if (OrgTypeEnum.DEPT.getValue() == oDO.getOrgType().intValue()) {
			if (isExistDeptName(oDO.getName(), null, oDO.getFatherorgId())) {
				throw new CrmBusinessException("同组织下部门名称不可重复");
			}
			if (isExistDeptSimpleName(oDO.getSimpleName(), null, oDO.getFatherorgId())) {
				throw new CrmBusinessException("同组织下部门简称不可重复");
			}
		}
		else if (OrgTypeEnum.COMPANY.getValue() == oDO.getOrgType().intValue()) {
			if (isExistCompanyName(oDO.getName(), null)) {
				throw new CrmBusinessException("公司名称不可重复");
			}
			if (isExistCompanySimpleName(oDO.getSimpleName(), null)) {
				throw new CrmBusinessException("公司简称不可重复");
			}
		}

		super.beforeSaveVO(oDO);
		
		oDO.setEnableState(EnableStateEnum.ENABLE.getValue());
	}

	/**
	 * 组织名称翻译
	 * @param ids
	 * @return
	 */
	public Object selectFieldsByIds(Object[] ids) {
		Map<String, Object> para = new HashMap<String, Object>();
		para.put("ids", ids);
		return dao.selectList(SysOrgDO.class, "selectFieldsByIds", para);
	}

	/**
	 * 更新数据
	 * @param vo
	 * @return
	 */
	public SysOrgVO update(SysOrgVO vo) {
		SysOrgDO oDO = ModelUtil.copyModel(vo, SysOrgDO.class);
		SysOrgVO resultVO =ModelUtil.copyModel(super.updateVO(oDO), SysOrgVO.class);
		trans(Arrays.asList(resultVO));
		return resultVO;
	}
	
	@Override
	protected void beforeUpdateVO(SysOrgDO oDO) {

		if (isExistCode(oDO.getCode(), oDO.getId())) {
			throw new CrmBusinessException("组织编码不可重复");
		}
		
		//同组织下部门名称、简称唯一
		if (OrgTypeEnum.DEPT.getValue() == oDO.getOrgType().intValue()) {
			if (isExistDeptName(oDO.getName(), oDO.getId(), oDO.getFatherorgId())) {
				throw new CrmBusinessException("同组织下部门名称不可重复");
			}
			if (isExistDeptSimpleName(oDO.getSimpleName(), oDO.getId(), oDO.getFatherorgId())) {
				throw new CrmBusinessException("同组织下部门简称不可重复");
			}
		}
		else if (OrgTypeEnum.COMPANY.getValue() == oDO.getOrgType().intValue()) {
			if (isExistCompanyName(oDO.getName(), oDO.getId())) {
				throw new CrmBusinessException("公司名称不可重复");
			}
			if (isExistCompanySimpleName(oDO.getSimpleName(), oDO.getId())) {
				throw new CrmBusinessException("公司简称不可重复");
			}
		}
		
		super.beforeUpdateVO(oDO);
	}

	/**
	 * 所有树
	 * @return
	 */
	public List<Map<String, Object>> getSysOrgTree() {
		List<Map<String, Object>> sysOrgTree = dao.selectList(SysOrgDO.class, "findSysOrgTree", null);
		return sysOrgTree;
	}
	
	/**
	 * 按类型查询组织树
	 * @param paraMap
	 * @return
	 */
	public List<Map<String, Object>> getTreeByOrgType(Integer orgType, Long fatherorgId,Long id) {
		
		Map<String, Object> paraMap = new HashMap<String, Object>();
		paraMap.put("orgType", orgType);
		paraMap.put("fatherorgId", fatherorgId);
		paraMap.put("id", id);
		
		List<Map<String, Object>> sysOrgTree = null;
		if(orgType.intValue() == OrgTypeEnum.GROUP.getValue()){
			sysOrgTree = dao.selectList(SysOrgDO.class, "findSysOrgTree", paraMap);
		}
		//获取公司及子公司
		else if (orgType.intValue() == OrgTypeEnum.COMPANY.getValue()) {
			sysOrgTree = dao.selectList(SysOrgDO.class, "findOrgTree", paraMap);
		}
		//获取部门及子部门
		else if (orgType.intValue() == OrgTypeEnum.DEPT.getValue()) {
			sysOrgTree = dao.selectList(SysOrgDO.class, "findDeptTree", paraMap);
		}

		return sysOrgTree;
	}
	
	/**
	 * 批量删除
	 * @param idStrs
	 * @return
	 */
	public int batchDelete(String[] ids) {
		//删除前添加判断
		/*
		 * 仅没有下级组织、没有人员 且 未关联商机、线索、客户、联系人等业务对象的组织，才可删除成功，否则提示“存在下级或关联业务单据，禁止删除”
		 */
		if(ids==null||ids.length==0)
			return 0;
		for(String id:ids){
			//获取下级组织
			Map<String, Object> paramMap=new HashMap<String, Object>();
			paramMap.put("deptId",Long.valueOf(id));
			List<Map<String, Object>> sysOrgChildrenList= getOrgByFatherId(paramMap);
			if(sysOrgChildrenList!=null&&sysOrgChildrenList.size()>0)
				return 2;
			paramMap.put("orgOrDeptId",Long.valueOf(id));
			int userCnt=userService.getCountByCondition(paramMap);
			if(userCnt>0)
				return 2;
			//联系人
			paramMap.put("org_id",Long.valueOf(id));
			int contactCnt=contactService.getCountByDeptOrOrg(paramMap);
			if(contactCnt>0)
				return 2;
			//客户
			
			//商机
			//线索
			
		}
		return super.batchDeleteByIDs(SysOrgDO.class, ids);
	}

	/**
	 * 批量停启用
	 * @param idArray
	 * @param enableState
	 * @return
	 */
	public String batchUpdateEnablestate(String[] ids, Integer enableState) {
		
		//停启用添加条件判断
		if(ids==null||ids.length==0)
			return "所选数据为空";
		if(enableState==2){
			for(String id:ids){
				//获取下级组织
				Map<String, Object> paramMap=new HashMap<String, Object>();
				paramMap.put("deptId",Long.valueOf(id));
				List<Map<String, Object>> sysOrgChildrenList= getOrgByFatherId(paramMap);
				for(Map <String, Object>map:sysOrgChildrenList){
					Integer enable_state=(Integer)map.get("enable_state");
					if(enable_state!=null&&enable_state==EnableStateEnum.ENABLE.getValue())
						return "存在未停用的下级组织，不可停用";
				}
				//当所选组织下存在未停用人员时、停用失败
				paramMap.put("orgOrDeptId",Long.valueOf(id));
				paramMap.put("enableState",1);
				int userCnt=userService.getCountByCondition(paramMap);
				if(userCnt>0)
					return "当所选组织下存在未停用人员时、停用失败";
			}
		}
		else if(enableState==1){
			//启用
			SysOrgVO sysOrg=null;
			for(String id:ids){
				//获取下级组织
				sysOrg=getDetail(Long.valueOf(id));
				SysOrgVO fatherSysOrg=getDetail(Long.valueOf(sysOrg.getFatherorgId()));
				if(fatherSysOrg!=null){
					if(fatherSysOrg.getEnableState()==EnableStateEnum.DISABLE.getValue())
						return "所选组织有未启用的上级组织，启用失败";
				}
			}
		}
		Map<String, Object> paraMap = new HashMap<String, Object>();
		paraMap.put("ids", ids);
		paraMap.put("enableState", enableState);
		dao.updateSql(SysOrgDO.class, "batchUpdateEnableState", paraMap);

		return enableState.intValue() == EnableStateEnum.ENABLE.getValue() ? "启用成功" : "停用成功";
	}
	
	/**
	 * 根据父级id获得组织
	 * @param paramMap
	 * @return
	 */
	public List<Map<String, Object>> getOrgByFatherId(Map<String, Object> paramMap) {
		return dao.selectList(SysOrgDO.class, "getOrgByFatherId", paramMap);
	}

	/*
	 * 获取所有部门列表(For云审同步)
	 */
	public List<Map<String, Object>> getAllDepts() {
		return dao.selectList(SysOrgDO.class, "getAllDepts", fillParaMapWithTenantId(null));
	}
	
	/**
	 * 移动端分页参照列表
	 * @param page
	 * @param paraMap
	 * @return
	 */
	public List<SysOrgVO> getRefervaluesForApp(Page<SysOrgVO> page, Map<String, Object> paraMap) {

		fillParaMapWithTenantId(paraMap);
		
		Page<SysOrgDO> doPage =  dao.pageSelect(SysOrgDO.class, page, "selectRefervalues", "countRefervalues", paraMap);
		Page<SysOrgVO> voPage = ModelUtil.copyPageModel(doPage, SysOrgVO.class);
		
		return voPage.getData();
	}
	
	/**
	 * 根据条件获得id集合
	 * @param paraMap
	 * @return
	 */
	public List<String> getIdsByCondition(Map<String, Object> paraMap) {
		
		fillParaMapWithTenantId(paraMap);
		
		return dao.selectStrList(SysOrgDO.class, "getIdsByCondition", paraMap);
	}
	/**
	 * 根据条件获得vo集合
	 * @param paraMap
	 * @return
	 */
	public List<SysOrgVO> getVosByCondition(Map<String, Object> paraMap) {
		fillParaMapWithTenantId(paraMap);
		List<SysOrgDO> sysOrgDO=dao.selectVoList(SysOrgDO.class, "getVosByCondition", paraMap);
		return ModelUtil.copyModelList(sysOrgDO,SysOrgVO.class);
	}
	
	/**
	 * 根据查询条件获得组织记录个数
	 * @param paraMap
	 * @return
	 */
	public int getCountByCondition(Map<String, Object> paraMap) {
		fillParaMapWithTenantId(paraMap);
		return dao.countAll(SysOrgDO.class, "getCountByCondition", paraMap);
	}
	
	/**
	 * 编码是否存在
	 * @param code
	 * @return
	 */
	private boolean isExistCode(String code, Long excludeId) {
		Map<String, Object> paraMap = new HashMap<String, Object>();
		paraMap.put("code", code);
		paraMap.put("excludeId", excludeId);
		return getCountByCondition(paraMap) > 0;
	}
	
	/**
	 * 公司简称是否存在
	 * @param name
	 * @param excludeId
	 * @param fatherorgId
	 * @return
	 */
	private boolean isExistCompanySimpleName(String simpleName, Long excludeId) {
		
		if (StringUtils.isNoneBlank(simpleName)) {
			Map<String, Object> paraMap = new HashMap<String, Object>();
			paraMap.put("simpleName", simpleName);
			paraMap.put("excludeId", excludeId);
			paraMap.put("orgType", OrgTypeEnum.COMPANY.getValue());
			return getCountByCondition(paraMap) > 0;
		}
		
		return false;
	}
	
	/**
	 * 公司名称是否存在
	 * @param name
	 * @param excludeId
	 * @param fatherorgId
	 * @return
	 */
	private boolean isExistCompanyName(String name, Long excludeId) {
		
		if (StringUtils.isNoneBlank(name)) {
			Map<String, Object> paraMap = new HashMap<String, Object>();
			paraMap.put("name", name);
			paraMap.put("excludeId", excludeId);
			paraMap.put("orgType", OrgTypeEnum.COMPANY.getValue());
			return getCountByCondition(paraMap) > 0;
		}
		
		return false;
	}
	
	
	/**
	 * 部门简称是否存在
	 * @param name
	 * @param excludeId
	 * @param fatherorgId
	 * @return
	 */
	private boolean isExistDeptSimpleName(String simpleName, Long excludeId, Long fatherorgId) {
		
		if (StringUtils.isNoneBlank(simpleName)) {
			Map<String, Object> paraMap = new HashMap<String, Object>();
			paraMap.put("simpleName", simpleName);
			paraMap.put("excludeId", excludeId);
			paraMap.put("fatherorgId", fatherorgId);
			paraMap.put("orgType", OrgTypeEnum.DEPT.getValue());
			return getCountByCondition(paraMap) > 0;
		}
		
		return false;
	}
	
	/**
	 * 部门名称是否存在
	 * @param name
	 * @param excludeId
	 * @param fatherorgId
	 * @return
	 */
	private boolean isExistDeptName(String name, Long excludeId, Long fatherorgId) {
		
		if (StringUtils.isNoneBlank(name)) {
			Map<String, Object> paraMap = new HashMap<String, Object>();
			paraMap.put("name", name);
			paraMap.put("excludeId", excludeId);
			paraMap.put("fatherorgId", fatherorgId);
			paraMap.put("orgType", OrgTypeEnum.DEPT.getValue());
			return getCountByCondition(paraMap) > 0;
		}
			
		return false;
	}
	
	/**
	 * 根据查询条件获得父级组织id集合
	 * @param paraMap
	 * @return
	 */
	public List<String> getFatherIdsByCondition(Map<String, Object> paraMap) {
		fillParaMapWithTenantId(paraMap);
		return dao.selectStrList(SysOrgDO.class, "getFatherIdsByCondition", paraMap);
	}
	
	private List<SysOrgVO> trans(List<SysOrgVO> voList) {
		List<FieldRelation<SysOrgVO>> relations = new ArrayList<FieldRelation<SysOrgVO>>();
		relations.add(new EnumFieldRelation<SysOrgVO>(SysOrgVO.class, "orgType", "orgTypeName", enumService, "org_type"));
		relations.add(new EnumFieldRelation<SysOrgVO>(SysOrgVO.class, "enableState", "enableStateName", enumService, "enable_state"));
		relations.add(new RefFieldRelation<SysOrgVO>(SysOrgVO.class, "fatherorgId", new String[]{"fatherorgName"}, orgService, "selectFieldsByIds"));
		new FieldRelationHandler<SysOrgVO>().handler(voList, relations);
		return voList;
	}
	
	/**
	 * 筛选部门id
	 * @param ids
	 * @return
	 */
	private List<String> getDeptIdByOrgId(String[] ids) {
		
		if (ids == null || ids.length == 0) {
			return null;
		}
		
		Map<String, Object> paraMap = new HashMap<String, Object>();
		paraMap.put("ids", ids);
		paraMap.put("orgType", OrgTypeEnum.DEPT.getValue());
		return getIdsByCondition(paraMap);
	}
	
	private Map<String, Object> fillParaMapWithTenantId(Map<String, Object> paraMap) {
		
		if (paraMap == null) {
			paraMap = new HashMap<String, Object>();
		}
		
		paraMap.put("tenantId", Long.parseLong(InvocationInfoProxy.getTenantid()));
		
		return paraMap;
	}

	/**
	 * 根据组织name过滤组织vo
	 * @param paraMap
	 * @return
	 */
	public List<Map<String, Object>> getSysOrgVoByCondition(Map<String, Object> paraMap) {
		return dao.selectList(SysOrgDO.class, "getSysOrgVoByCondition", paraMap);
	}

	private Page<SysOrgDO> getPageWithFilter(Page<SysOrgDO> doPage) {
		Long orgid=Long.valueOf((String) InvocationInfoProxy.getParameter("orgid"));
		List<Map<String, Object>> sysOrgList=getTreeByOrgType(OrgTypeEnum.GROUP.getValue(), null,orgid);
		List<Long> ids=new ArrayList<Long>();
		getIdFromTree(sysOrgList,ids);
		if(ids.size()==0 ||doPage==null)
			return null;
		List<SysOrgDO> listData=doPage.getData();
		List<SysOrgDO> newListData=new ArrayList<SysOrgDO>();
		for(SysOrgDO sysOrg:listData){
			
			if(sysOrg!=null&&ids.contains(sysOrg.getId())){
				newListData.add(sysOrg);
			}
		}
		doPage.setData(newListData);
		return doPage;
	}

	private void getIdFromTree(List<Map<String, Object>> sysOrgList,
			List<Long> ids) {
		if(sysOrgList==null||sysOrgList.size()==0)
			return;
		for(Map<String, Object> sysOrgMap:sysOrgList){
			BigInteger bigInter=(BigInteger)sysOrgMap.get("id");
			if(bigInter==null)
				return;
			ids.add(bigInter.longValue());
			List<Map<String, Object>> childen=(List<Map<String, Object>>)sysOrgMap.get("children");
			getIdFromTree(childen,ids);
		}
	}
}
